/**
 * 
 */
package edu.asu.sapa.ground.update;

import edu.asu.sapa.ground.State;
import edu.asu.sapa.heuristic.PG;
import edu.asu.sapa.utils.Priority;

public final class UpdateWrapper<T extends Update> extends Priority<Update> {
	public final static int Start_Finish = 0x1;
	public final static int Instant_Interval = 0x2;
	public final static int Before_After = 0x4; // must be the high bit, so that type1 < type2 orders 'Before' before 'After'

	public final static int UpdateBefore = 0x0; 
		// 0x1 could be taken just as easily; an update both starts and finishes.
	public final static int StartBefore = 0x2;
	public final static int FinishBefore = 0x3;
	public final static int UpdateAfter = 0x4;
		// 0x5 could be taken just as easily; an update both starts and finishes.
	public final static int StartAfter = 0x6;
	public final static int FinishAfter = 0x7;
	
	public Context c;
	public float time;
	public int type;
	
	public UpdateWrapper() {
		super();
		c = null;
		time = 0;
	}
	public UpdateWrapper(Context c, Update u, int type, float time) {
		super(u);
		this.c = c;
		this.type = type;
		this.time = time;
	}
	public UpdateWrapper<T> clone() {
		return (UpdateWrapper<T>) super.clone();
	}
	public UpdateWrapper<T> set(Update u, float time) {
		this.event = u;
		this.time = time;
		return this;
	}
	public final UpdateWrapper<T> set(Context c, Update u, int type, float time) {
		this.c = c;
		this.event = u;
		this.type = type;
		this.time = time;
		return this;
	}
	public final int compareTo(Priority<Update> w) {
		return compareTo((UpdateWrapper<T>) w);
	}
	public final int compareTo(UpdateWrapper<T> w) {
		if (time == w.time) {
			return type - w.type;
		}
		return (int) (time - w.time);
	}
	
	public final boolean process(State s) {
		switch(type) {
		case UpdateBefore:
			return this.event.updateBefore(s, c, time);
		case UpdateAfter:
			return this.event.updateAfter(s, c, time);
		case StartBefore:
			return this.event.startAfter(s, c, time);
		case FinishBefore:
			return this.event.finishBefore(s, c, time);
		case StartAfter:
			return this.event.startAfter(s, c, time);
		case FinishAfter:
			return this.event.finishAfter(s, c, time);
		}
		return false;
	}
	
	public void relaxedUpdate(PG pg, State s) {
		switch(type) {
		case UpdateBefore:
			this.event.relaxedUpdate(pg,s,c,time);
			break;
		case UpdateAfter:
			this.event.relaxedUpdate(pg,s,c,time);
			break;
		case StartBefore:
			this.event.relaxedStart(pg,s,c,time);
			break;
		case FinishBefore:
			this.event.relaxedFinish(pg,s,c,time);
			break;
		case StartAfter:
			this.event.relaxedStart(pg,s,c,time);
			break;
		case FinishAfter:
			this.event.relaxedFinish(pg,s,c,time);
			break;
		}
	}
}
